package com.emeraldparser.util;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.Multimap;
import com.google.common.collect.Multiset;
import com.google.common.collect.Table;
import com.google.common.collect.Table.Cell;

/**
 * An interface to complement {@link Table}. Any similarities are on purpose.
 * 
 * @author Adam Paynter
 *
 * @param <R> the type of the table row keys
 * @param <C> the type of the table column keys
 * @param <V> the type of the mapped values
 */
public interface Multitable<R, C, V> {

	/**
	 * Returns the number of row key / column key / value mappings in the multitable.
	 * 
	 * @return
	 */
	int size();

	/**
	 * Returns {@code true} if the multitable contains no mappings.
	 * 
	 * @return
	 */
	boolean isEmpty();

	/**
	 * Returns {@code true} if the multitable contains a mapping with the specified
	 * row and column keys.
	 * 
	 * @param rowKey key of row to search for
	 * @param columnKey key of column to search for
	 * @return
	 */
	boolean contains(Object rowKey, Object columnKey);

	/**
	 * Returns {@code true} if the multitable contains a mapping with the specified
	 * row key.
	 * 
	 * @param rowKey key of row to search for
	 * @return
	 */
	boolean containsRow(Object rowKey);

	/**
	 * Returns {@code true} if the multitable contains a mapping with the specified
	 * column key.
	 * 
	 * @param columnKey key of column to search for
	 * @return
	 */
	boolean containsColumn(Object columnKey);

	/**
	 * Returns {@code true} if the multitable contains a mapping with the specified
	 * value.
	 * 
	 * @param value value to search for
	 * @return
	 */
	boolean containsValue(Object value);

	Collection<V> get(R rowKey, C columnKey);

	/**
	 * Returns the hash code for this multitable. The hash code of a multitable is defined as
	 * the hash code of the table view, as returned by {@link #asTable()}.
	 * 
	 * @return
	 */
	int hashCode();

	/**
	 * Compares the specified object with this multitable for equality. Two
	 * multitables are equal when their table views, as returned by
	 * {@link #asTable()}, are also equal.
	 * 
	 * @param obj
	 * @return
	 */
	boolean equals(Object obj);

	/**
	 * Removes all mappings from the multitable.
	 * 
	 */
	void clear();

	/**
	 * <p>Stores a row-column-value mapping in the multitable.</p>
	 * 
	 * <p>Some multitable implementations allow duplicate row-column-value mappings,
	 * in which case {@code put} always adds a new row-column-value mapping and increases
	 * the multitable size by 1. Other implementations prohibit duplicates, and storing
	 * a row-column-value mapping that's already in the multitable has no effect.</p>
	 * 
	 * @param rowKey row key that the value should be associated with
	 * @param columnKey column key that the value should be associated with
	 * @param value value to be associated with the specified keys
	 * 
	 */
	boolean put(R rowKey, C columnKey, V value);

	boolean putAll(Multitable<? extends R, ? extends C, ? extends V> multitable);

	boolean putAll(R rowKey, C columnKey, Iterable<? extends V> values);

	boolean remove(Object rowKey, Object columnKey, Object value);

	Collection<V> removeAll(Object rowKey, Object columnKey);

	Multimap<C, V> row(R rowKey);

	Multimap<R, V> column(C columnKey);

	Collection<Cell<R, C, V>> cells();

	Set<R> rowKeySet();

	Multiset<R> rowKeys();

	Set<C> columnKeySet();

	Multiset<C> columnKeys();

	Collection<V> values();

	Map<R, ? extends Multimap<C, V>> rowMap();

	Map<C, ? extends Multimap<R, V>> columnMap();

	Table<R, C, ? extends Collection<V>> asTable();

}
